package com.wquick.base.weight.maskSwitch

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.view.animation.AccelerateDecelerateInterpolator
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.drawscope.clipRect
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalView
import androidx.core.animation.addListener
import androidx.core.graphics.applyCanvas
import kotlin.math.hypot
import kotlin.math.roundToInt

// ### 思路
//
//截图遮挡下层进行遮罩，下层切换好后上层使用paint进行混合绘制来显示下层，就达到了切换的效果
//
//### 步骤
//
//1. 获取当前页面截图。注(Compose获取截图时是通过LocalView进行获取，所以有节点树顺序影响，所以需要放在最外层)
//2. 获取截图后绘制到页面上层遮住下方，绘制结束后走一个绘制结束回调进行主题切换。注(切换的时间一般是无感知的，所以不用关心同步等待问题)
//3. 以页面对角线长度为半径使用Paint进行与截图图层的混合
//4. 根据动画模式选择paint的模式是擦除还是相交显示
//5. 使用ValueAnimator.ofFloat创建动画来进行圆的绘制，绘制结束后显示下层已经切换好的页面结束动画


// MaskSwitchBox(
//    animTime =1000L, //动画时间(毫秒为单位)
//    maskComplete = {},//截图创建完成的回调，也就是动画准备完成开始直接的回调
//    animFinish = { },//动画结束后的回调
//) { maskAnimActiveEvent ->
//    Button(onClick = {
//        //调用函数激活动画，传入动画类型，动画扩展收缩的圆形的坐标，可以认为是点击坐标
//        maskAnimActiveEvent(MaskSwitchAnimModel.EXPEND,0f,0f)
//    }) {
//        Text(text = "active mask anim")
//    }
//}

enum class MaskSwitchAnimModel {
    EXPEND,
    SHRINK,
}

/**
 * 激活遮罩动画，
 * 动画模式，点击的x坐标，点击的y坐标
 */
typealias MaskSwitchAnimActive = (MaskSwitchAnimModel, Float, Float) -> Unit

@SuppressLint("Recycle")
@Composable
fun MaskSwitchBox(
    animTime: Long = 698,
    maskComplete: (MaskSwitchAnimModel) -> Unit,
    animFinish: () -> Unit,
    content: @Composable BoxScope.(MaskSwitchAnimActive) -> Unit,
) {
    val rootView = LocalView.current.rootView
    var maskAnimModel by remember {
        mutableStateOf(MaskSwitchAnimModel.EXPEND)
    }
    val paint by remember {
        mutableStateOf(Paint(Paint.ANTI_ALIAS_FLAG))
    }
    var clickX by remember { mutableStateOf(0f) }
    var clickY by remember { mutableStateOf(0f) }
    var viewBounds by remember { mutableStateOf<Rect?>(null) }
    var viewScreenshot by remember { mutableStateOf<Bitmap?>(null) }
    var maskRadius by remember {
        mutableStateOf(0f)
    }

    val maskAnimActive: MaskSwitchAnimActive = clickEvent@{ animModel, x, y ->
        clickX = x
        clickY = y
        val bitmapBound = viewBounds ?: return@clickEvent
        val radiusRange = when (animModel) {
            MaskSwitchAnimModel.EXPEND -> Pair(0f, hypot(rootView.width.toFloat(), rootView.height.toFloat()))

            MaskSwitchAnimModel.SHRINK -> Pair(hypot(rootView.width.toFloat(), rootView.height.toFloat()), 0f)
        }
        maskAnimModel = animModel
        viewScreenshot = Bitmap
            .createBitmap(
                bitmapBound.width.roundToInt(),
                bitmapBound.height.roundToInt(),
                Bitmap.Config.ARGB_8888
            )
            .applyCanvas {
                translate(-bitmapBound.left, -bitmapBound.top)
                rootView.draw(this)
                maskComplete(animModel)
            }

        ValueAnimator.ofFloat(radiusRange.first, radiusRange.second)
            .apply {
                duration = animTime
                interpolator = AccelerateDecelerateInterpolator()
                addUpdateListener { valueAnimator ->
                    maskRadius = valueAnimator.animatedValue as Float
                }
                addListener(onEnd = {
                    viewScreenshot = null
                    animFinish()
                })
            }.start()
    }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .onGloballyPositioned {
                viewBounds = it.boundsInWindow()
            }
            .drawWithCache {
                onDrawWithContent {
                    clipRect {
                        this@onDrawWithContent.drawContent()
                    }

                    viewScreenshot?.let { bmp ->
                        with(drawContext.canvas.nativeCanvas) {
                            val layer = saveLayer(null, null)
                            when (maskAnimModel) {
                                MaskSwitchAnimModel.EXPEND -> {
                                    drawBitmap(bmp, 0f, 0f, null)
                                    paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
                                    drawCircle(clickX, clickY, maskRadius, paint)
                                }

                                MaskSwitchAnimModel.SHRINK -> {
                                    drawCircle(clickX, clickY, maskRadius, paint)
                                    paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
                                    drawBitmap(bmp, 0f, 0f, paint)
                                }
                            }
                            paint.xfermode = null
                            restoreToCount(layer)
                        }
                    }
                }
            }

    ) {
        content(maskAnimActive)
    }
}

